package com.mybatisx.mybatisplus.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mybatisx.mybatisplus.activiti.rest.editor.ProcessDiagramGeneratorNew;
import com.mybatisx.mybatisplus.common.response.CommonCode;
import com.mybatisx.mybatisplus.common.response.QueryResponseResult;
import com.mybatisx.mybatisplus.common.response.QueryResult;
import com.mybatisx.mybatisplus.common.response.ResponseResult;
import com.mybatisx.mybatisplus.dto.LeaveDTO;
import com.mybatisx.mybatisplus.entity.*;
import com.mybatisx.mybatisplus.mapper.ActHiVarinstMapper;
import com.mybatisx.mybatisplus.mapper.ActReModelMapper;
import com.mybatisx.mybatisplus.mapper.ActRuVariableMapper;
import com.mybatisx.mybatisplus.mapper.LeaveMapper;
import com.mybatisx.mybatisplus.service.ActReModelService;
import com.mybatisx.mybatisplus.service.LeaveProcessService;
import lombok.extern.log4j.Log4j2;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author wuyue
 * @date 2021/9/3 10:49
 */

@Service
@Log4j2
public class LeaveProcessServiceImpl implements LeaveProcessService {

    @Autowired
    private LeaveMapper leaveMapper;
    @Autowired
    private ActRuVariableMapper actRuVariableMapper;
    @Autowired
    private ActHiVarinstMapper actHiVarinstMapper;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RepositoryService repositoryService;

    @Override
    public QueryResponseResult getList(LeaveDTO in) {
        //设置条件
        QueryWrapper<ActRuVariable> wrapper = new QueryWrapper<>();
        //eq是等于，ge是大于等于，gt是大于，le是小于等于，lt是小于，like是模糊查询
        wrapper.like("NAME_", "leaveMessage");  //请假流程记录
        List<ActRuVariable> actRuVariables = actRuVariableMapper.selectList(wrapper);
        List<Leaveprocess> leave = new ArrayList<>();
        for (ActRuVariable act : actRuVariables) {
            Leaveprocess leaveprocess = JSONObject.parseObject(act.getText(), Leaveprocess.class);
            leaveprocess.setProcInstId(act.getProcInstId());
            leave.add(leaveprocess);
        }
        leave = leave.stream().filter(p -> p.getPersonId().equals(in.getPersonId())).collect(Collectors.toList());

        if (StringUtils.isNotBlank(in.getDescription())) {
            leave = leave.stream().filter(p -> p.getDescription().contains(in.getDescription())).collect(Collectors.toList());
        }
        QueryResult queryResult = new QueryResult();
        queryResult.setTotal(leave.size());
        queryResult.setList(listSplit(leave, in.getPageSize(), in.getPageNum()));
        return new QueryResponseResult(CommonCode.SUCCESS, queryResult);
    }

    @Override
    public QueryResponseResult getHistoryList(LeaveDTO in) {
        //设置条件
        QueryWrapper<ActHiVarinst> wrapper = new QueryWrapper<>();
        QueryWrapper<ActRuVariable> wrapper1 = new QueryWrapper<>();
        //eq是等于，ge是大于等于，gt是大于，le是小于等于，lt是小于，like是模糊查询
        wrapper.like("NAME_", "leaveMessage");  //请假流程记录
        wrapper1.like("NAME_", "leaveMessage");  //请假流程记录
        List<ActHiVarinst> actHiVarinsts = actHiVarinstMapper.selectList(wrapper);
        List<Leaveprocess> leave = new ArrayList<>();
        for (ActHiVarinst act : actHiVarinsts) {
            Leaveprocess leaveprocess = JSONObject.parseObject(act.getText(), Leaveprocess.class);
            leaveprocess.setProcInstId(act.getProcInstId());
            //判断审核状态
            Task task = taskService.createTaskQuery().processInstanceId(act.getProcInstId()).singleResult();
            if (Objects.isNull(task)) {
                leaveprocess.setStateString("已结束");   //已结束
                leaveprocess.setState(1);
            }else{
                leaveprocess.setStateString(task.getName());
                leaveprocess.setState(0);
            }

            leave.add(leaveprocess);
        }
        leave = leave.stream().filter(p -> p.getPersonId().equals(in.getPersonId())).collect(Collectors.toList());

        if (StringUtils.isNotBlank(in.getDescription())) {
            leave = leave.stream().filter(p -> p.getDescription().contains(in.getDescription())).collect(Collectors.toList());
        }
        QueryResult queryResult = new QueryResult();
        queryResult.setTotal(leave.size());
        queryResult.setList(listSplit(leave, in.getPageSize(), in.getPageNum()));
        return new QueryResponseResult(CommonCode.SUCCESS, queryResult);
    }

    /**
     * 对集合分页
     */
    private List listSplit(List list, Integer pageSize, Integer pageNum) {
        List newList = null;
        int total = list.size();
        newList = list.subList(pageSize * (pageNum - 1), ((pageSize * pageNum) > total ? total : (pageSize * pageNum)));
        return newList;
    }


    /**
     * 获取需要高亮的线
     *
     * @param processDefinitionEntity
     * @param historicActivityInstances
     * @return
     */
    private List<String> getHighLightedFlows(ProcessDefinitionEntity processDefinitionEntity,
                                             List<HistoricActivityInstance> historicActivityInstances) {

        List<String> highFlows = new ArrayList<String>();// 用以保存高亮的线flowId
        for (int i = 0; i < historicActivityInstances.size() - 1; i++) {// 对历史流程节点进行遍历
            ActivityImpl activityImpl = processDefinitionEntity
                    .findActivity(historicActivityInstances.get(i).getActivityId());// 得到节点定义的详细信息
            List<ActivityImpl> sameStartTimeNodes = new ArrayList<ActivityImpl>();// 用以保存后需开始时间相同的节点
            ActivityImpl sameActivityImpl1 = processDefinitionEntity
                    .findActivity(historicActivityInstances.get(i + 1).getActivityId());
            // 将后面第一个节点放在时间相同节点的集合里
            sameStartTimeNodes.add(sameActivityImpl1);
            for (int j = i + 1; j < historicActivityInstances.size() - 1; j++) {
                HistoricActivityInstance activityImpl1 = historicActivityInstances.get(j);// 后续第一个节点
                HistoricActivityInstance activityImpl2 = historicActivityInstances.get(j + 1);// 后续第二个节点
                if (activityImpl1.getStartTime().equals(activityImpl2.getStartTime())) {
                    // 如果第一个节点和第二个节点开始时间相同保存
                    ActivityImpl sameActivityImpl2 = processDefinitionEntity
                            .findActivity(activityImpl2.getActivityId());
                    sameStartTimeNodes.add(sameActivityImpl2);
                } else {
                    // 有不相同跳出循环
                    break;
                }
            }
            List<PvmTransition> pvmTransitions = activityImpl.getOutgoingTransitions();// 取出节点的所有出去的线
            for (PvmTransition pvmTransition : pvmTransitions) {
                // 对所有的线进行遍历
                ActivityImpl pvmActivityImpl = (ActivityImpl) pvmTransition.getDestination();
                // 如果取出的线的目标节点存在时间相同的节点里，保存该线的id，进行高亮显示
                if (sameStartTimeNodes.contains(pvmActivityImpl)) {
                    highFlows.add(pvmTransition.getId());
                }
            }
        }
        return highFlows;
    }

    @Override
    public InputStream getActPlanView(String processInstanceId) {
        // 获取历史流程实例
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();
        // 获取流程定义
        ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
                .getDeployedProcessDefinition(historicProcessInstance.getProcessDefinitionId());
        List<HistoricActivityInstance> historicActivityInstanceList = historyService
                .createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
                .orderByHistoricActivityInstanceStartTime().asc().list();

        // 已执行的节点ID集合
        List<String> executedActivityIdList = new ArrayList<String>();
        int index = 1;
        for (HistoricActivityInstance activityInstance : historicActivityInstanceList) {
            /*if(activityInstance.getEndTime()!=null){*///这个地方主要是获取了所有的流程 原本是不要当前流程
            executedActivityIdList.add(activityInstance.getActivityId());
            index++;
            /*	}*/
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");

        /*获取流程list*/
        //另一种获取已经到的节点
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        List<HistoricTaskInstance> hisToryList = engine.getHistoryService() // 历史相关Service
                .createHistoricTaskInstanceQuery() // 创建历史活动实例查询
                .processInstanceId(processInstanceId) // 执行流程实例id
                .finished()
                .list();

        List<ActDrawVo> list = new ArrayList<>();
        for (HistoricTaskInstance h : hisToryList) {
            ActDrawVo adv1 = new ActDrawVo();
            adv1.setRoleCode("personnal");
            adv1.setName("张三");
            adv1.setSignTime(sdf.format(h.getEndTime()));
            list.add(adv1);
        }
        // 获取流程图图像字符流
        InputStream imageStream = null;
        try {
            List<String> hlist = justflowList(processInstanceId);
            imageStream = ProcessDiagramGeneratorNew.generateDiagram(processDefinition, "png",
                    executedActivityIdList, processInstanceId, list, hlist);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            log.error(e.getMessage(), e);
        }

        return imageStream;
    }


    /*只给id获得线路集合*/
    private List<String> justflowList(String procId) {
        String processInstanceId = procId;
        // 获取历史流程实例
        HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();
        ProcessDefinitionEntity definitionEntity = (ProcessDefinitionEntity) repositoryService
                .getProcessDefinition(processInstance.getProcessDefinitionId());
        // 第一种.高亮目前走过的节点
        List<HistoricActivityInstance> highLightedActivitList = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processInstanceId).list();
        // 高亮线路id集合
        List<String> highLightedFlows = getHighLightedFlows(definitionEntity, highLightedActivitList);
        return highLightedFlows;
    }
}
